"""POI detection service."""
import math
from typing import Optional
from app import db
from app.models.location import Location
from app.models.poi import POI
from app.models.walking_session import WalkingSession


class POIDetectorService:
    """Service for detecting nearby POIs."""
    
    DETECTION_RANGE_METERS = 30
    
    def check_nearby_pois(
        self,
        user_location: Location,
        session_id: str
    ) -> Optional[POI]:
        """Check if user is near any unvisited POIs.
        
        Args:
            user_location: User's current location
            session_id: Current session ID
            
        Returns:
            Nearby POI if found, None otherwise
        """
        # Get the session to check visited POIs
        session = WalkingSession.query.get(session_id)
        if not session:
            return None
        
        # Get visited POI IDs for deduplication
        visited_poi_ids = session.visited_poi_ids or []
        
        # Get all POIs from database
        all_pois = POI.query.all()
        
        # Check each POI for proximity
        for poi in all_pois:
            # Skip if already visited in this session
            if poi.id in visited_poi_ids:
                continue
            
            # Create Location object for POI
            poi_location = Location(
                latitude=poi.latitude,
                longitude=poi.longitude,
                accuracy=1.0  # POI locations are precise
            )
            
            # Calculate distance
            distance = self.calculate_distance(user_location, poi_location)
            
            # Check if within detection range
            if distance <= self.DETECTION_RANGE_METERS:
                return poi
        
        return None
    
    def mark_poi_visited(
        self,
        session_id: str,
        poi_id: str
    ) -> None:
        """Mark POI as visited in session.
        
        Args:
            session_id: Session ID
            poi_id: POI ID
        """
        session = WalkingSession.query.get(session_id)
        if not session:
            return
        
        # Initialize visited_poi_ids if None
        if session.visited_poi_ids is None:
            session.visited_poi_ids = []
        
        # Add POI ID if not already in list (deduplication)
        if poi_id not in session.visited_poi_ids:
            session.visited_poi_ids.append(poi_id)
            db.session.commit()
    
    def calculate_distance(
        self,
        loc1: Location,
        loc2: Location
    ) -> float:
        """Calculate distance between two locations using Haversine formula.
        
        Args:
            loc1: First location
            loc2: Second location
            
        Returns:
            Distance in meters
        """
        # Earth radius in meters
        R = 6371000
        
        # Convert to radians
        lat1_rad = math.radians(loc1.latitude)
        lat2_rad = math.radians(loc2.latitude)
        delta_lat = math.radians(loc2.latitude - loc1.latitude)
        delta_lon = math.radians(loc2.longitude - loc1.longitude)
        
        # Haversine formula
        a = (math.sin(delta_lat / 2) ** 2 +
             math.cos(lat1_rad) * math.cos(lat2_rad) *
             math.sin(delta_lon / 2) ** 2)
        c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
        
        distance = R * c
        return distance
